// src/ai/ai.service.ts
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import * as https from 'https';
import { User } from '../../user/entity/user.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';

const SYSTEM_JSON_ONLY = [
  '严格JSON模式：你必须只输出一个JSON对象，不能包含任何额外文字、注释、前后缀或代码块围栏。',
  '不得使用 ``` 或 ```json。',
  '对象必须包含字段：polishedMessage(string)、reasoning(string)、confidence(number, 0~1)。',
  '若内容中包含引号需正确转义；不得输出 null/undefined；confidence 必须是数字而非字符串。',
].join(' ');

@Injectable()
export class AiService {
  private readonly apiKey: string;
  private readonly baseUrl: string;

  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {
    this.apiKey = 'sk-5917b78c998149d79703b5be13401799';
    this.baseUrl = 'https://dashscope.aliyuncs.com/compatible-mode/v1/';
  }

  async polishMessage(
    originalMessage: string,
    sender: User,
    receiver: User,
    chatType: 'friend' | 'group' = 'friend',
  ): Promise<{
    polishedMessage: string;
    reasoning: string;
    confidence: number;
  }> {
    const prompt = this.buildPrompt(
      originalMessage,
      sender,
      receiver,
      chatType,
    );

    try {
      const result = await this.makeApiRequest(prompt);
      console.log('结果是', result);
      return this.parseAiResponse(result);
    } catch (error) {
      throw new HttpException(
        'AI服务暂时不可用',
        HttpStatus.SERVICE_UNAVAILABLE,
      );
    }
  }

  private buildPrompt(
    originalMessage: string,
    sender: User,
    receiver: User,
    chatType: 'friend' | 'group' = 'friend',
  ): string {
    return `请根据以下信息，对情侣间的原始消息进行“仅表达层面”的润色（不改变原意），并据此产出 JSON 对象中的字段：

发送方信息：
- MBTI人格：${sender.mbti || '未知'}
- 性别：${sender.sex || '未知'}
- 年龄：${sender.birthday ? this.calculateAge(sender.birthday) : '未知'}

接收方信息：
- MBTI人格：${receiver.mbti || '未知'}
- 性别：${receiver.sex || '未知'}
- 年龄：${receiver.birthday ? this.calculateAge(receiver.birthday) : '未知'}

双方关系：情侣
聊天类型：${chatType === 'friend' ? '私聊' : '群聊'}
原始消息：${JSON.stringify(originalMessage)}

润色要求：
1. 体现亲密与爱意，但不过分夸张；群聊需适度克制、私聊可更亲密。
2. 充分考虑接收方 MBTI 与性别偏好；同时保留发送方 MBTI 的表达风格。
3. 不改变原意，只优化措辞与语气，提高被接受度与温暖感。
4. 语言风格自然、口语化；避免冒犯、PUA 或强控制语气。
5. 中文输出。

输出字段说明（仅输出一个JSON对象，不要代码块围栏）：
- polishedMessage: string，润色后的消息（尽量 ≤ 40 字，群聊≤ 30 字更稳）。
- reasoning: string，简述润色理由与考虑因素（≤ 100 字）。
- confidence: number，0~1 的可信度。
`;
  }

  async makeApiRequest(prompt: string): Promise<string> {
    const url = new URL('chat/completions', this.baseUrl);
    const requestBody = JSON.stringify({
      model: 'qwen-plus', // 也可用 qwen-plus（同属 qwen3 系列）
      messages: [
        { role: 'system', content: SYSTEM_JSON_ONLY },
        { role: 'user', content: prompt },
      ],
      temperature: 0.7,
      max_tokens: 1000,
    });

    const options: https.RequestOptions = {
      protocol: url.protocol,
      hostname: url.hostname,
      path: url.pathname + url.search, // /compatible-mode/v1/chat/completions
      method: 'POST',
      headers: {
        Authorization: `Bearer ${this.apiKey}`, // 必须：DASHSCOPE_API_KEY
        'Content-Type': 'application/json',
        Accept: 'application/json',
        'Content-Length': Buffer.byteLength(requestBody),
      },
      timeout: 10000,
    };

    return new Promise<string>((resolve, reject) => {
      const req = https.request(options, res => {
        // let responseData = res;
        // console.log('结果是', responseData);

        let data = '';
        res.setEncoding('utf8');
        res.on('data', chunk => {
          data += chunk;
        });

        res.on('end', () => {
          const ok =
            res.statusCode && res.statusCode >= 200 && res.statusCode < 300;
          if (!ok)
            return reject(new Error(`API请求失败: ${res.statusCode} ${data}`));
          try {
            const json = JSON.parse(data);
            const content = json?.choices?.[0]?.message?.content ?? '';
            resolve(content);
          } catch (e) {
            console.log('错误发生了0', e);
            reject(
              new Error(
                `响应解析失败: ${(e as Error).message}. 原始响应: ${data}`,
              ),
            );
          }
        });
      });

      req.on('error', err => reject(err));
      req.on('timeout', () => {
        req.destroy();
        reject(new Error('请求超时'));
      });

      req.write(requestBody);
      req.end();
    });
  }

  private parseAiResponse(
    aiResponse: string,
  ): { polishedMessage: string; reasoning: string; confidence: number } {
    // 小工具：默认返回
    const fallback = (
      msg: string,
      reason = 'AI直接返回了润色结果',
      conf = 0.7,
    ) => ({
      polishedMessage: msg,
      reasoning: reason,
      confidence: conf,
    });

    // 1) 尝试把输入当“完整API JSON”解析（含 choices[0].message.content）
    let raw = aiResponse;
    try {
      const top = JSON.parse(aiResponse);

      // 情况 A：AI 直接返回的就是目标 JSON（含 polishedMessage 等字段）
      if (
        top &&
        typeof top === 'object' &&
        ('polishedMessage' in top || 'reasoning' in top || 'confidence' in top)
      ) {
        return {
          polishedMessage: String(top.polishedMessage ?? ''),
          reasoning: String(top.reasoning ?? ''),
          confidence: Number(top.confidence ?? 0.8),
        };
      }

      // 情况 B：OpenAI-compatible 响应，提取 content
      const content = top?.choices?.[0]?.message?.content;
      if (typeof content === 'string') {
        raw = content;
      }
    } catch {
      // 不是完整 JSON，就把原样字符串继续走下面的流程
    }

    // 2) 去掉可能的代码块围栏，例如 ```json ... ```
    const fence = raw.match(/```(?:json|javascript|js)?\s*([\s\S]*?)\s*```/i);
    if (fence) raw = fence[1];
    raw = raw.trim().replace(/^\uFEFF/, ''); // 去 BOM

    // 3) 直接把剩余内容当 JSON 试一次
    try {
      const obj = JSON.parse(raw);
      return {
        polishedMessage: String(obj.polishedMessage ?? ''),
        reasoning: String(obj.reasoning ?? 'AI返回了结构化结果'),
        confidence: Number(obj.confidence ?? 0.8),
      };
    } catch {
      // 继续尝试提取花括号中的 JSON 片段
    }

    // 4) 从文本中截取第一个 { …… } 片段再解析（兼容前后有解释文字）
    const start = raw.indexOf('{');
    const end = raw.lastIndexOf('}');
    if (start !== -1 && end > start) {
      const maybeJson = raw.slice(start, end + 1);
      try {
        const obj = JSON.parse(maybeJson);
        return {
          polishedMessage: String(obj.polishedMessage ?? ''),
          reasoning: String(obj.reasoning ?? 'AI返回了半结构化结果'),
          confidence: Number(obj.confidence ?? 0.8),
        };
      } catch {
        // 忽略，走兜底
      }
    }

    // 5) 兜底：当成普通文本
    return fallback(raw);
  }

  private calculateAge(birthday: string): number {
    if (!birthday) return 0;

    try {
      const birthDate = new Date(birthday);
      const today = new Date();
      let age = today.getFullYear() - birthDate.getFullYear();
      const monthDiff = today.getMonth() - birthDate.getMonth();

      if (
        monthDiff < 0 ||
        (monthDiff === 0 && today.getDate() < birthDate.getDate())
      ) {
        age--;
      }
      return age;
    } catch (error) {
      return 0;
    }
  }
}
